This document provides information about merging part editors into one shared library.
Table of Contents
-------------------------
• A C++ Shared Library for ODF
• A Shared Library Containing Multiple Part Editors
• Final Notes
The standard way of building ODF parts is to statically link the four ODF static libraries with your editor-specific code into one shared library (which is dynamically linked to ODFLibrary). Using this approach, there is a minimum of about 200K of ODF code that will be linked into your part editors. If you are developing a suite of editors, you may want to explore ways to share the ODF code among the editors in your suite. There are two options you might consider: creating a shared library for the ODF static libraries that is separate from your part editors, or create a single shared library containing ODF and your part editors
A C++ Shared Library for ODF
You can build a single shared library containing the four ODF static libraries and possibly include other code that you write and that is shared across your part suite. Unfortunately, there are several downsides to this approach. You'll be exporting C++ functions, for which there are no standard shared library calling conventions. This will restrict you to one compiler vendor, and probably even just one specific release from that compiler vendor. For example, if you used CodeWarrior 7 to build C++ shared libraries you would have had to rebuild them all in order to upgrade to CodeWarrior 8 (CW8 changed v-table layout and name mangling). However, there is an even bigger problem with this approach. ODF defines about 7000 member functions, and potentially all of these need to be exported. This results in a significant amount of Code Fragment Manager overhead, and probably eliminates any advantage gained by sharing code.
We do NOT recommend using this option.
A Shared Library Containing Multiple Part Editors
A second option is to simply create one shared library (i.e. one code fragment) containing multiple part editors. This shared library would statically link to ODF but not export any ODF-specific interfaces. Each SOM class would be exported as usual, so if you have three part editors you would need at least three exports (for the SOM ClassData structures for the three subclasses of ODPart). If one or more of the parts support embedding then you'll also need exports for the subclasses of ODEmbeddedFramesIterator. Likewise if your parts define any subclasses of ODExtension, etc.
There are several things that are appealing about this approach but that are not without their downsides. If one of the part editors in your suite is a relatively small viewer, it will probably require less than 200K of code from the ODF static libraries, while adding 20-30K of part-specific code. If another part is a complex part supporting embedding, it might require 350K (possibly more) of code from ODF, while adding 200K-300K of part-specific code. Combining these two parts into one shared library will save the 200K of common ODF code, but all of the remaining code (approximately 500K of code) will be loaded whenever either of the part editors is in use, whether the other editor is in use or not. If your user is using virtual memory, this may not be a significant problem, but if virtual memory is turned off, the entire code fragment will be loaded into the process manager heap. This may mean that you should only merge part editors into one shared library if they are very likely to all be active at the same time.
The ODF team has conducted a simple experiment by building a single shared library containing ODFDraw, ODFBitmap, and ODFNothing. The resulting part editors work without any known problems though we have not yet thoroughly tested them. We've included the projects for making this merged shared library in the "Tools & Goodies" folder. Here's what we did:
1) Isolate the editor-specific code for each part editor.
The easiest way to merge all of the code is to create one static library per part editor, and then link all of the ODF static libraries and your part editor static libraries in a final step. To create a static library of the code for one part editor, simply duplicate the IDE project, change the project preferences to generate a static library, and remove everything from the project except the source files specific to the part editor.
2) Resolve nmap resource ID conflicts.
Every part editor in the merged library must have its own nmap resources. The IDs used for nmaps in ODF parts are assigned in the "Binding.k" file. The Binding.k file generated by ODF PartMaker templates will use the same resource IDs, so you will need to edit the Binding.k for each of your part editors.
3) Resolve all other resource ID conflicts.
When parts are built separately from the same PartMaker templates, they're likely to have resource ID conflicts. For example, all parts will probably use the same resource ID for their menu bar resource. When the parts are merged into one shared library, each menu bar will have to be given a unique resource ID. By convention, resource IDs are specified in the "Defines.k" and "Binding.k" files. Resource IDs are also hard-coded in the "MacIcons.rsrc" files. All of these files may need to be edited to eliminate resource ID conflicts.
4) Create Bundle resources for the merged shared library
Your bundle resource having the signature 'odtm' will need two entries per part. See the file "bndl.r" for an example of how you might do this.
5) Create a 'cfrg' resource
Standard part editors need a cfrg resource containing two entries (per architecture). A merged shared library will need two entries per part (per architecture), plus possibly another entry to satisfy your debugger. See the cfrg.r file in the ODFMerged project for an example.
6) Merge all of the pieces together
You'll need an IDE project (or a makefile) that includes all of the static libraries for your parts, the ODF libraries, the OpenDoc stub libraries, and all of the necessary resource files. You can create this project by copying a standard part editor project, removing all part-specific sources (included resources), retaining all of the ODF libraries, OpenDoc stubs, and system libraries. Add to this project the static libraries for each of your part editors (created in step 1).
You will also need to include all needed resources from each part editor. We did this by creating a rez source file named "Merged.r" which simply included all of the resources from each of the individual part editor (which means that individual part editors must be built first). This file looked like this:
include "ODFNothing" 'nmap';
include "ODFNothing" 'icl4';
....
include "ODFBitmap" 'nmap';
include "ODFBitmap" 'icl4';
...
include "ODFDraw" 'nmap';
include "ODFDraw" 'icl4';
...
Final Notes
It's not currently possible to build stationery for all parts in a merged shared library by dropping the library onto the OpenDoc™ launcher application. You'll probably want to build individual shared libraries during development, so plan to use stationery made from these libraries.
If you have trouble debugging your merged library, make sure you have an entry in your 'cfrg' resource that is named consistently with the project that built the merged library. For example, the ODFMerged project was named ODFMerged.π, the shared library was named ODFMerged, and the 'cfrg' resource contains one entry named "ODFMerged".